----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    15:56:52 08/12/2015 
-- Design Name: 
-- Module Name:    frequence_counter - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity frequence_counter is
    Port ( hclk : in  STD_LOGIC;
           clr : in  STD_LOGIC;
           md : in  STD_LOGIC_VECTOR (1 downto 0);
			  test_cnt_out : out STD_LOGIC_VECTOR (7 downto 0);
           rd_clk : out  STD_LOGIC;
           rd_en : in  STD_LOGIC;
           fin_x : in  STD_LOGIC;
			  fin_x_dvd : in  STD_LOGIC;
			  fin_x_sel : in	STD_LOGIC;
           fin_y : in  STD_LOGIC;
           dout_0 : out  STD_LOGIC;
           dout_x : out  STD_LOGIC;
           dout_y : out  STD_LOGIC;
           ready : out  STD_LOGIC);
--			  test_in : in STD_LOGIC;
--			  test_out : out STD_LOGIC);
end frequence_counter;

architecture Behavioral of frequence_counter is
	
	COMPONENT counter
	PORT(
		clk : IN  std_logic;
		clr : IN  std_logic;
		en : IN  std_logic;
		cnt : OUT  std_logic_vector(31 downto 0));
	END COMPONENT;
	
	COMPONENT dtrigger
	PORT(
		din : IN  std_logic;
		clk : IN  std_logic;
		dout : OUT  std_logic;
		ndout : OUT  std_logic);
	END COMPONENT;
	
	COMPONENT shift_register
	PORT(
		clk : IN  std_logic;
		en_input : IN  std_logic;
		en_output : IN  std_logic;
		din : IN  std_logic_vector(31 downto 0);
		dout : OUT  std_logic);
	END COMPONENT;

	-- internal signals
	signal hclk_d10 : STD_LOGIC := '0';
	signal syc_rd_clk : STD_LOGIC := '0';
	signal nsyc_rd_clk : STD_LOGIC := '1';
	signal internal_en : STD_LOGIC := '0';
	signal counter_en : STD_LOGIC := '0';
	signal ncounter_en : STD_LOGIC := '1';
	signal xcounter_en : STD_LOGIC := '0';
	signal counter_clk : STD_LOGIC := '0';
	signal fin_sel : STD_LOGIC := '0';
	signal int_finx : STD_LOGIC := '0';
	signal int_finy : STD_LOGIC := '0';
	signal en_input : STD_LOGIC := '0';
	signal int_data_0 : std_logic_vector(31 downto 0) := (others => '0');
	signal int_data_x : std_logic_vector(31 downto 0) := (others => '0');
	signal int_data_y : std_logic_vector(31 downto 0) := (others => '0');
	
	-- output_signals
	signal signal_dout_0 : STD_LOGIC := '0';
	signal signal_dout_x : STD_LOGIC := '0';
	signal signal_dout_y : STD_LOGIC := '0';
	signal signal_ready : STD_LOGIC := '0';
	signal signal_rd_clk : STD_LOGIC := '0';
	signal signal_test_out : STD_LOGIC := '0';
begin

--test_cnt_out <= int_data_0(19 downto 12);
test_cnt_out(7) <= signal_ready;
test_cnt_out(6) <= hclk;
test_cnt_out(5) <= fin_x;
test_cnt_out(4) <= '1';
test_cnt_out(3 downto 0) <= "0000";

syc_rd_clk <= signal_rd_clk;

int_finx <= ((fin_x and (not fin_x_sel)) or (fin_x_dvd and fin_x_sel));
int_finy <= (md(1) and md(0) and fin_y);
--int_finy <= fin_y;

-- Internal enable justice
--process(md)
--begin
--	if (md = "00") then
--		internal_en <= '0';
--	else
--		internal_en <= '1';
--	end if;
--end process;
internal_en <= (md(1) or md(0));

-- Counter enable justice
process(int_finx, int_finy, xcounter_en)
begin
	if (md(1) = '1') then
	if (md(0) = '0') then
		fin_sel <= ((xcounter_en and (not int_finx)) or ((not xcounter_en) and int_finx));
	else
		fin_sel <= ((xcounter_en and int_finy) or ((not xcounter_en) and int_finx));
	end if;
	end if;
end process;
process(fin_sel, counter_en)
begin
	if (md(1) = '0') then
		xcounter_en <= '0';
	else
		if (fin_sel'event and fin_sel='1') then
			xcounter_en <= not xcounter_en;
		end if;
	end if;
end process;

-- Counter clock_in justice
process(int_finx, hclk)
begin
	if (md(1) = '0') then
		counter_clk <= int_finx;
	else
		counter_clk <= hclk;
	end if;
end process;

-- 10-devide of hclk
process(hclk)
	variable hclk_iter : integer range 0 to 9 := 0;
begin
	if (hclk'event and hclk='1') then
		if (hclk_iter=0) then
			hclk_d10 <= '1';
			hclk_iter := hclk_iter + 1;
		elsif (hclk_iter=5) then
			hclk_d10 <= '0';
			hclk_iter := hclk_iter + 1;
		elsif (hclk_iter=9) then
			hclk_iter := 0;
		else
			hclk_iter := hclk_iter + 1;
		end if;
	end if;
end process;

-- test program
--test_out <= signal_test_out;
--signal_test_out <= test_in;
process(signal_rd_clk)
begin
	if (signal_rd_clk'event and signal_rd_clk='1') then
		signal_test_out <= signal_test_out nand '1';
	end if;
end process;

-- output signals
dout_0 <= signal_dout_0;
dout_x <= signal_dout_x;
dout_y <= signal_dout_y;
ready <= signal_ready;

rd_clk <= signal_rd_clk;
-- make read clock: 50kHz
process(hclk)
	constant hclk_devider : integer := 1000;
	variable hclk_iter : integer range 0 to (hclk_devider - 1) := 0;
begin
	if (hclk'event and hclk='1') then
		if (hclk_iter=0) then
			signal_rd_clk <= '1' and rd_en;
			hclk_iter := hclk_iter + 1;
		elsif (hclk_iter=hclk_devider/2) then
			signal_rd_clk <= '0';
			hclk_iter := hclk_iter + 1;
		elsif (hclk_iter=hclk_devider - 1) then
			hclk_iter := 0;
		else
			hclk_iter := hclk_iter + 1;
		end if;
	end if;
end process;

-- calculate ready state
c_ready: process(counter_en, rd_en)
begin
	signal_ready <= counter_en nor rd_en;
end process;

-- make components
input_trigger: dtrigger
	PORT MAP (
		din => internal_en,
		clk => int_finx,
		dout => counter_en,
		ndout => ncounter_en);
counter_0: counter
	PORT MAP (
		clk => hclk,
		clr => clr,
		en => counter_en,
		cnt => int_data_0);
counter_x: counter
	PORT MAP (
		clk => int_finx,
		clr => clr,
		en => counter_en,
		cnt => int_data_x);
counter_y: counter
	PORT MAP (
		clk => counter_clk,
		clr => clr,
		en => xcounter_en,
		cnt => int_data_y);
register_0: shift_register
	PORT MAP (
		clk => syc_rd_clk,
		en_input => signal_ready,
		en_output => rd_en,
		din => int_data_0,
		dout => signal_dout_0);
register_x: shift_register
	PORT MAP (
		clk => syc_rd_clk,
		en_input => signal_ready,
		en_output => rd_en,
		din => int_data_x,
		dout => signal_dout_x);
register_y: shift_register
	PORT MAP (
		clk => syc_rd_clk,
		en_input => signal_ready,
		en_output => rd_en,
		din => int_data_y,
		dout => signal_dout_y);

end Behavioral;

